package com.wuyangnju.lj.simulation.slave;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.List;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.map.ObjectMapper;

import com.wuyangnju.lj.simulation.common.CommonStrings;
import com.wuyangnju.lj.simulation.common.Plan;
import com.wuyangnju.lj.simulation.common.SlaveTask;

public class SlaveMainThread {

	public static final int RETRY_GAP = 60;

	private static Log log = LogFactory.getLog(SlaveMainThread.class);
	private static HttpClient client = new HttpClient();
	private static ObjectMapper mapper = new ObjectMapper();

	// private static PrintWriter planlistLog;

	public static void run(SlaveCnf cnf) {

		// try {
		// File log = new File("planlist_" + cnf.getThreadId() + ".log");
		// if (!log.exists()) {
		// log.createNewFile();
		// }
		// planlistLog = new PrintWriter(new FileWriter(log, true), true);
		// } catch (IOException e) {
		// e.printStackTrace();
		// }

		while (true) {
			int retCode = Integer.MIN_VALUE;
			InputStreamReader isr = null;
			BufferedReader br = null;
			String requestJson = null;

			try {
				GetMethod method = new GetMethod("http://"
						+ cnf.getMasterHost() + ":" + cnf.getMasterPort() + "/"
						+ cnf.getLocationPrefix() + "/"
						+ CommonStrings.REQUEST_SLAVE_TASK + "?threadId="
						+ cnf.getThreadId());
				retCode = client.executeMethod(method);
				isr = new InputStreamReader(method.getResponseBodyAsStream());
				br = new BufferedReader(isr);
				requestJson = br.readLine();

				if (requestJson.startsWith(CommonStrings.COMPUTION_EXCEPTION)) {
					log.warn("compution not yet initialized, sleep "
							+ RETRY_GAP + "s and try again.");
					Thread.sleep(RETRY_GAP * 1000);
					continue;
				}
			} catch (IOException e) {
				log.warn("connection fail, try again. return code: " + retCode,
						e);
				try {
					Thread.sleep(RETRY_GAP * 1000);
				} catch (InterruptedException e1) {
					log.error(e1, e1);
				}
				continue;
			} catch (InterruptedException e) {
				log.error("unexpected slave main thread interrupted", e);
				continue;
			}
			log.info("get task json: " + requestJson);

			SlaveTask request = null;
			try {
				request = mapper.readValue(requestJson, SlaveTask.class);
			} catch (Exception e) {
				log.error("request json parse fail, sleep " + RETRY_GAP
						+ "s and try to reconnect.", e);
				try {
					Thread.sleep(RETRY_GAP * 1000);
				} catch (InterruptedException e1) {
					log.error(e1, e1);
				}
				continue;
			}
			log.info("parse task json success");

			List<Plan> plans = request.getPlans();
			Collections.shuffle(plans);

			StringBuilder sb = new StringBuilder();
			for (Plan plan : plans) {
				sb.append(plan + " ");
			}
			// planlistLog.println(sb.toString());

			for (Plan plan : plans) {
				double dataItem = Double.MIN_VALUE;
				retCode = Integer.MIN_VALUE;
				String dataItemId = null;
				try {
					dataItem = Inventory.inventory(plan.getX1(), plan.getX2(),
							plan.getX3(), plan.getX4(), plan.getX5());

					PostMethod method = new PostMethod("http://"
							+ cnf.getMasterHost() + ":" + cnf.getMasterPort()
							+ "/" + cnf.getLocationPrefix() + "/"
							+ CommonStrings.SUBMIT_DATA_ITEM);
					method.addParameter(CommonStrings.PLAN_X1,
							"" + plan.getX1());
					method.addParameter(CommonStrings.PLAN_X2,
							"" + plan.getX2());
					method.addParameter(CommonStrings.PLAN_X3,
							"" + plan.getX3());
					method.addParameter(CommonStrings.PLAN_X4,
							"" + plan.getX4());
					method.addParameter(CommonStrings.PLAN_X5,
							"" + plan.getX5());
					method.addParameter(CommonStrings.DATA_ITEM, "" + dataItem);
					retCode = client.executeMethod(method);
					dataItemId = method.getResponseBodyAsString();

				} catch (IOException e) {
					log.warn("generate data for " + plan
							+ " fail, skip. retCode: " + retCode, e);
					continue;
				}
				log.info("generate data for " + plan + ": " + dataItem
						+ " with dataItemId: " + dataItemId + " retCode: "
						+ retCode);
			}
		}
	}
}
